package com.yuecai.modules.security.rest;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yuecai.config.WxMaConfiguration;
import com.yuecai.modules.security.JwtUserDto;
import com.yuecai.modules.security.config.bean.LoginProperties;
import com.yuecai.modules.security.config.bean.SecurityProperties;
import com.yuecai.modules.security.security.TokenProvider;
import com.yuecai.modules.security.service.OnlineUserService;
import com.yuecai.modules.security.service.SmsCodeAuthenticationToken;
import com.yuecai.modules.security.service.dto.AuthDto;
import com.yuecai.modules.yc_coupon.service.YcCouponService;
import com.yuecai.modules.yc_order.service.utils.MakeOrderNum;
import com.yuecai.modules.yc_user.domain.YcUser;
import com.yuecai.modules.yc_user.domain.YcUserWechat;
import com.yuecai.modules.yc_user.repository.YcUserRepository;
import com.yuecai.modules.yc_user.service.YcUserWechatService;
import lombok.AllArgsConstructor;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * 微信小程序用户接口
 *
 * @author <a href="https://github.com/binarywang">Binary Wang</a>
 */
@RestController
@AllArgsConstructor
@RequestMapping("/auth/api/wx/user")
public class WxMaUserController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    private final RedisTemplate redisTemplate;
    private final ObjectMapper objectMapper;
    private final YcUserWechatService ycUserWechatService;
    private final SecurityProperties properties;
    private final OnlineUserService onlineUserService;
    private final TokenProvider tokenProvider;
    private final AuthenticationManager authenticationManager;
    private final LoginProperties loginProperties;
    private final PasswordEncoder passwordEncoder;
    private final YcUserRepository ycUserRepository;
    private final YcCouponService ycCouponService;

    /**
     * 登陆接口
     */
    @GetMapping("/login")
    public ResponseEntity<Object> login(String code, HttpServletRequest request) throws WxErrorException {
        final WxMaService wxService = WxMaConfiguration.getMaService("wxd5945d01cfdc29fc");
        WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(code);
        String openid = session.getOpenid();
        YcUserWechat byOpenId = ycUserWechatService.findByOpenId(openid);
        if (byOpenId!=null){
            Optional<YcUser> byId = ycUserRepository.findById(byOpenId.getUserId());
            YcUser ycUser = byId.get();
            String phone = ycUser.getPhone();
            SmsCodeAuthenticationToken authenticationToken =
                    new SmsCodeAuthenticationToken(phone,null);

            Authentication authentication = authenticationManager.authenticate(authenticationToken);
            SecurityContextHolder.getContext().setAuthentication(authentication);
            // 生成令牌
            String token = tokenProvider.createToken(authentication);
            final JwtUserDto jwtUserDto = (JwtUserDto) authentication.getPrincipal();
            // 保存在线信息
            onlineUserService.save(jwtUserDto, token, request);
            // 返回 token 与 用户信息
            Map<String, Object> authInfo = new HashMap<String, Object>(2) {{
                put("token", properties.getTokenStartWith() + token);
                put("user", jwtUserDto);
            }};
            if (loginProperties.isSingleLogin()) {
                //踢掉之前已经登录的token
                onlineUserService.checkLoginOnUser(phone, token);
            }
            return ResponseEntity.ok(authInfo);
        }else {
            HashMap<String, String> map = new HashMap<>();
            String sessionKey = session.getSessionKey();

            String makeTradeNum = MakeOrderNum.makeTradeNum();
            redisTemplate.opsForHash().put(makeTradeNum, "openid", openid);
            redisTemplate.opsForHash().put(makeTradeNum, "session_key", sessionKey);
            redisTemplate.expire(makeTradeNum, 10, TimeUnit.MINUTES);
            System.out.println(makeTradeNum + "----------111-----------" + sessionKey);
            map.put("cache_key", makeTradeNum);
            return ResponseEntity.ok(map);
        }
    }

    /**
     * <pre>
     * 获取用户信息接口
     * </pre>
     */
    @PostMapping("/binding")
    @Transactional(rollbackFor = Exception.class)
    public ResponseEntity<Object> info(@Validated @RequestBody AuthDto authDto, HttpServletRequest request) throws JsonProcessingException {
        String phone = authDto.getPhone();
        String cache_key = authDto.getCache_key();
        String sessionKey = (String) redisTemplate.opsForHash().get(cache_key, "session_key");
        if (StringUtils.isBlank(sessionKey)){
            return ResponseEntity.status(HttpStatus.BAD_GATEWAY.value()).body("会话失效！");
        }

        System.out.println(cache_key+"----------------------"+sessionKey+"======"+objectMapper.writeValueAsString(authDto));
        final WxMaService wxService = WxMaConfiguration.getMaService("wxd5945d01cfdc29fc");
        // 解密用户信息
        WxMaUserInfo userInfo = wxService.getUserService().getUserInfo(sessionKey, authDto.getEncryptedData(), authDto.getIv());
        YcUser byName = ycUserRepository.findByPhone(phone);
        redisTemplate.delete(cache_key);
        YcUserWechat wechat = new YcUserWechat();
        wechat.setAvatarUrl(userInfo.getAvatarUrl());
        wechat.setCity(userInfo.getCity());
        wechat.setCountry(userInfo.getCountry());
        wechat.setProvince(userInfo.getProvince());
        wechat.setGender(Integer.valueOf(userInfo.getGender()));
        wechat.setNickName(userInfo.getNickName());
        wechat.setOpenId(userInfo.getOpenId());
        wechat.setUnionId(userInfo.getUnionId());
        wechat.setCreateTime(new Timestamp(System.currentTimeMillis()));

        if (byName == null) {
            byName = new YcUser();
            byName.setPhone(phone);
            byName.setLevel(1);
            byName.setState(0);
            byName.setState(0);
            byName.setImgUrl(userInfo.getAvatarUrl());
            byName.setPassword(passwordEncoder.encode("123456"));
            byName.setReferralCode(MakeOrderNum.referralCode());
            String referralCode = authDto.getReferralCode();
            if (StringUtils.isNotBlank(referralCode)){
                Optional<YcUser> byReferralCode = ycUserRepository.findByReferralCode(referralCode);
                if (byReferralCode.isPresent()){
                    byName.setPid(byReferralCode.get().getId());
                }
            }
            YcUser save = ycUserRepository.save(byName);
            if (save != null) {
                ycCouponService.register(save.getId(),save.getPid());
            }
        }
        byName.setImgUrl(userInfo.getAvatarUrl());
        byName.setNickName(userInfo.getNickName());
        ycUserRepository.save(byName);
        wechat.setUserId(byName.getId());
        ycUserWechatService.create(wechat);
        SmsCodeAuthenticationToken authenticationToken =
                new SmsCodeAuthenticationToken(phone,authDto.getReferralCode());

        Authentication authentication = authenticationManager.authenticate(authenticationToken);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        // 生成令牌
        String token = tokenProvider.createToken(authentication);
        final JwtUserDto jwtUserDto = (JwtUserDto) authentication.getPrincipal();
        // 保存在线信息
        onlineUserService.save(jwtUserDto, token, request);
        // 返回 token 与 用户信息
        Map<String, Object> authInfo = new HashMap<String, Object>(2) {{
            put("token", properties.getTokenStartWith() + token);
            put("user", jwtUserDto);
        }};
        if (loginProperties.isSingleLogin()) {
            //踢掉之前已经登录的token
            onlineUserService.checkLoginOnUser(phone, token);
        }
        return ResponseEntity.ok(authInfo);
    }

//
//    /**
//     * <pre>
//     * 获取用户绑定手机号信息
//     * </pre>
//     */
//    @GetMapping("/phone")
//    public String phone(String sessionKey, String signature,
//                        String rawData, String encryptedData, String iv) {
//
//        // 用户信息校验
//        if (!wxService.getUserService().checkUserInfo(sessionKey, rawData, signature)) {
//            return "user check failed";
//        }
//
//        // 解密
//        WxMaPhoneNumberInfo phoneNoInfo = wxService.getUserService().getPhoneNoInfo(sessionKey, encryptedData, iv);
//
//        return "JsonUtils.toJson(phoneNoInfo)";
//    }

}
